package com.yc.wxcontroller;

import com.yc.common.utils.JsonUtils;
import com.yc.endpointer.ClockEndpoint;
import com.yc.entity.Attendance;
import com.yc.entity.AttendanceRecords;
import com.yc.entity.Schedule;
import com.yc.exception.BizException;
import com.yc.mapper.ScheduleMapper;
import com.yc.service.AttendanceRecordsService;
import com.yc.service.AttendanceService;
import com.yc.service.ScheduleService;
import com.yc.service.StudentInfoService;
import com.yc.vo.AttendanceData;
import com.yc.vo.Result;
import com.yc.vo.StudentAttendanceRecord;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author zhupanlin
 * @version 1.0
 * @description: TODO
 * @date 2023/7/24 11:04
 */
@Api("微信管理考勤控制器")
@RestController
@RequestMapping("/wx/attendance")
public class WXAttendanceController {
    @Resource
    AttendanceService attendanceService;

    @Resource
    AttendanceRecordsService attendanceRecordsService;

    @Resource
    ScheduleService scheduleService;

    @Resource
    StudentInfoService studentInfoService;

    @Resource
    ScheduleMapper scheduleMapper;

    @Resource
    RedisTemplate redisTemplate;

    // 定时任务线程池，线程数为CPU的2倍
    public static ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 2);

    @ApiOperation("查询当前老师上课班级的学生")
    @GetMapping("/get/{username}")
    public Result selectStudentBySchedule(@ApiParam(name = "username", value = "上课老师的工号", required = true)
                                          @PathVariable("username") String username) {
        return Result.success(attendanceService.selectStudentByAttId(username));
    }

    @ApiOperation("查询当前这节课是否有考勤记录")
    @GetMapping("/getAttId/{username}")
    public Result selectAttId(@ApiParam(name = "username", value = "上课老师的工号", required = true)
                              @PathVariable("username") String username,
                              @RequestParam("classId") String classId) {
        Schedule schedule = scheduleService.selectScheduleByCidAndDate(username, classId);
        // 插入之前查询是否有记录
        Integer attId = attendanceService.selectAttendanceByScheduleId(schedule.getId() + "");
        return Result.success(attId);
    }

    @ApiOperation("手动添加考勤信息")
    @PostMapping("/add/{username}")
    public Result addAttendance(@ApiParam(name = "username", value = "上课老师的工号", required = true)
                                @PathVariable("username") String username,
                                @RequestParam("classId") String classId, @RequestParam("arrivecount") Integer arrivecount) {
        Attendance attendance = new Attendance();
        attendance.setClassId(classId);
        attendance.setArrivedcount(arrivecount);
        attendance.setCreateBy(username);
        attendance.setUpdateBy(username);
        attendance.setSignmethod(4);

        Schedule schedule = scheduleService.selectScheduleByCidAndDate(username, classId);
        attendance.setScheduleid(schedule.getId());
        // 插入之前查询是否有记录
        Integer attId = attendanceService.selectAttendanceByScheduleId(schedule.getId() + "");
        attendance.setId(attId);
        Result result;
        // 有记录 则 修改 没有 就新增
        if (attId == null || attId <= 0) {
            attendanceService.addAttendance(attendance);
            result = new Result(1, attendance.getId());
            result.setMsg("添加成功!");
        } else {
            // 修改
            attendanceService.modifyAttendance(attendance);
            result = new Result(1, attId);
            result.setMsg("添加成功!");
        }
        return result;
    }


    @ApiOperation("查询学生有考勤的年份")
    @GetMapping("/get/allyears/{stuid}")
    public Result selectAllYears(@ApiParam(name = "stuid", value = "学生学号", required = true)
                                 @PathVariable("stuid") String stuid) {
        List<String> years = attendanceService.selectAllYears(stuid);
        return Result.success(years);
    }

    @ApiOperation("查询学生有考勤的月份")
    @GetMapping("/get/allmonths/{beginDate}")
    public Result selectAllMonths(@ApiParam(name = "beginDate", value = "考勤的年份", required = true)
                                  @PathVariable("beginDate") Integer beginDate) {
        List<String> dates = attendanceRecordsService.selectNowSchoolYear(beginDate);
        List<String> months = attendanceService.selectAllMonths(dates.get(0), dates.get(1));
        //List<String> months = attendanceService.selectAllMonths("2023-07-01", "2024-07-01");
        return Result.success(months);
    }

    @ApiOperation("老师发布快捷考勤")
    @PostMapping("/quickDeploy")
    public Result quickDeploy(@RequestBody List<AttendanceData> attendancelist) throws BizException {
        final Integer integer = attendanceService.addQuick(attendancelist);
        if (integer > 0) {
            return Result.success("发布成功");
        }
        return Result.error("发布失败");
    }

    @ApiOperation("捕获Biz异常")
    @ExceptionHandler(BizException.class)
    public Result handelBizException(BizException e) {
        return Result.error(e.getMessage());
    }

    @ApiOperation("生成暗号")
    @PostMapping("/produceKey/{key}/{username}")
    public Result produceKey(@ApiParam(name = "key", value = "暗号")
                             @PathVariable("key") String key,
                             @ApiParam(name = "username", value = "用户名")
                             @PathVariable("username") String username,
                             @RequestBody List<String> cids,
                             HttpServletRequest request) {
        // 设置为子线程共享
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        RequestContextHolder.setRequestAttributes(ra, true);
        Random rd = new Random();
        boolean flag = false;
        if ("0".equals(key)) {
            // 如果暗号为0
            // 生成一个6位数的暗号，出现重复的概率为1/10^6
            key = rd.nextInt(10) + "";
            for (int i = 0; i < 5; i++) {
                key += rd.nextInt(10);
            }
            // 开启定时任务
            flag = true;
        }
        // 查询学生存入redis中
        Object list = studentInfoService.selectStudentsByCidForWx(key, cids);
        // 定时任务
        String finalKey = key;
        // 防止重复开启定时任务
        if (flag) {
            ScheduledFuture<?> schedule = stpe.schedule(new Runnable() {
                @Override
                public void run() {
                    System.out.println("定时任务启动");
                    // 添加考勤记录
                    attendanceService.addAttendanceForWx(finalKey, username);
                }
            }, 6, TimeUnit.MINUTES);
        }

        Map<String, Object> map = new HashMap<>();
        map.put("key", finalKey);
        map.put("list", list);
        return Result.success(map);
    }

    // 输入暗号时调用
    @ApiOperation("获取输入暗号的信息")
    @GetMapping("/get/info/{key}/{stuid}/{stuname}/{cid}")
    public Result getInfo(@ApiParam(name = "key", value = "暗号", required = true)
                          @PathVariable("key") String key,
                          @ApiParam(name = "stuid", value = "扫码学生的学号", required = true)
                          @PathVariable("stuid") String stuid,
                          @ApiParam(name = "stuname", value = "扫码学生的姓名", required = true)
                          @PathVariable("stuname") String stuname,
                          @ApiParam(name = "cid", value = "班级编号", required = true)
                          @PathVariable("cid") String cid) {
        //成功之后就开始改变查询出来的状态
        ClockEndpoint clockEndpoint = ClockEndpoint.onlineClocking.get(key);
        if (clockEndpoint == null) {
            return Result.error("考勤完毕，修改请找上课老师!");
        }

        //改变缓存当中的状态
        Map<String, String> data = (Map<String, String>) redisTemplate.opsForValue().get(key);
        assert data != null;
        String redisKey = cid + "-" + stuid + "-" + stuname;
        if (data.containsKey(redisKey)) {
            String value = data.get(redisKey);
            if ("1".equals(value.substring(0, 1))) {
                return Result.success("请勿重复签到!");
            }
            data.put(redisKey, "1" + data.get(redisKey).substring(1));
            redisTemplate.opsForValue().set(key, data);
            //改变页面的状态的前提条件
            Map<String, String> messaage = new ConcurrentHashMap<>();
            messaage.put("cid", cid);
            messaage.put("stuid", stuid);
            messaage.put("sname", stuname);
            messaage.put("status", "已到");
            // 拍照学生 将拍照的图片发送给前端
            String str = JsonUtils.objectToJson(messaage);
            clockEndpoint.onMessage(key, str);
            return Result.success("签到成功!");
        } else {
            return Result.error("签到失败,没有该用户!");
        }
        //再修改
    }

    @ApiOperation("修改学生状态信息")
    @GetMapping("/modify/info/{key}/{stuid}/{stuname}/{cid}")
    public Result modifyInfo(@ApiParam(name = "key", value = "暗号", required = true)
                             @PathVariable("key") String key,
                             @ApiParam(name = "stuid", value = "扫码学生的学号", required = true)
                             @PathVariable("stuid") String stuid,
                             @ApiParam(name = "stuname", value = "扫码学生的姓名", required = true)
                             @PathVariable("stuname") String stuname,
                             @ApiParam(name = "cid", value = "班级编号", required = true)
                             @PathVariable("cid") String cid) {
        //成功之后就开始改变查询出来的状态
        ClockEndpoint clockEndpoint = ClockEndpoint.onlineClocking.get(key);
        if (clockEndpoint == null) {
            return Result.error("考勤完毕，时间已到");
        }

        //改变缓存当中的状态
        Map<String, String> data = (Map<String, String>) redisTemplate.opsForValue().get(key);
        assert data != null;
        String redisKey = cid + "-" + stuid + "-" + stuname;
        if (data.containsKey(redisKey)) {
            String value = data.get(redisKey);
            if ("1".equals(value.substring(0, 1))) {
                return Result.success("请勿重复签到!");
            }
            data.put(redisKey, "1" + data.get(redisKey).substring(1));
            redisTemplate.opsForValue().set(key, data);
            return Result.success("修改成功!");
        } else {
            return Result.error("修改失败,请联系管理员!");
        }
        //再修改
    }
}
